#include "grflib_stdafx.h"
#include <DXUTgui.h>
#include <SDKmisc.h>
#include "../include/grflibEffects.h"
#include <D3Dcompiler.h>
#include "../include/Hash.h"
#include "../include/D3D10Engine.h"
#include "../include/Material.h"
#include "../include/Texture.h"

namespace grflib { namespace engine { namespace aux {

CBlinnPhongEffect::CBlinnPhongEffect()
{
    m_filename = _T("grflibBlinnPhong.fxo");
    AddTechnique("Render");
    AddTechnique("RenderNoCull");
    AddTechnique("FaceNormal");
    AddTechnique("Color");
    AddShaderVariable("World", CEffect::SVUSE_MATRIX);
    AddShaderVariable("View", CEffect::SVUSE_MATRIX);
    AddShaderVariable("Projection", CEffect::SVUSE_MATRIX);
    AddShaderVariable("AmbientTexture", CEffect::SVUSE_SHADER_RESOURCE);
    AddShaderVariable("DiffuseTexture", CEffect::SVUSE_SHADER_RESOURCE);
    AddShaderVariable("AlphaTexture", CEffect::SVUSE_SHADER_RESOURCE);
    AddShaderVariable("SpecularTexture", CEffect::SVUSE_SHADER_RESOURCE);
    AddShaderVariable("Kd", CEffect::SVUSE_VECTOR);
    AddShaderVariable("Ka", CEffect::SVUSE_VECTOR);
    AddShaderVariable("Ks", CEffect::SVUSE_VECTOR);
    AddShaderVariable("MaterialAlpha", CEffect::SVUSE_SCALAR);
    AddShaderVariable("MaterialSpecularity", CEffect::SVUSE_SCALAR);
    AddShaderVariable("HasAmbientTexture", CEffect::SVUSE_SCALAR);
    AddShaderVariable("HasDiffuseTexture", CEffect::SVUSE_SCALAR);
    AddShaderVariable("HasAlphaTexture", CEffect::SVUSE_SCALAR);
    AddShaderVariable("HasSpecularTexture", CEffect::SVUSE_SCALAR);
}

CBlinnPhongEffect::~CBlinnPhongEffect()
{
}

using namespace engine::core;
HRESULT CBlinnPhongEffect::SetShaderVariables(boost::shared_ptr<CMaterial> &pMaterial, const std::string &strTechnique)
{
    HRESULT hr;
    
    if ("Render" == strTechnique 
        || "RenderNoCull" == strTechnique
        || "FaceNormal" == strTechnique)
    {
        ID3D10EffectVectorVariable *pVecVar;
        ID3D10EffectShaderResourceVariable *pSRVar;
        ID3D10EffectScalarVariable *pScalarVar, *pScalarVar2;
        CMaterial::texture_slot_type::iterator iter;

        //set diffuse texture
        pScalarVar = GetShaderVariable("HasAmbientTexture")->AsScalar();
        if ((iter = pMaterial->textureSlots.find("ambient")) != pMaterial->textureSlots.end())
        {
            CTexture2D *pTex2D = boost::dynamic_pointer_cast<CTexture2D>( _ResrcMan.FindObj(iter->second) ).get();
            if (pTex2D)
            { 
                pSRVar = GetShaderVariable("AmbientTexture")->AsShaderResource();
                V_RETURN( pSRVar->SetResource(pTex2D->GetShaderResourceView()) ); 
                V_RETURN( pScalarVar->SetBool(true) );
            }
        }
        else
        {
            pVecVar = GetShaderVariable("Ka")->AsVector();
            V_RETURN( pVecVar->SetFloatVector(pMaterial->ambient) );
            V_RETURN( pScalarVar->SetBool(false) );
        }

        //set diffuse texture
        pScalarVar = GetShaderVariable("HasDiffuseTexture")->AsScalar();
        if ((iter = pMaterial->textureSlots.find("diffuse")) != pMaterial->textureSlots.end())
        {
            CTexture2D *pTex2D = boost::dynamic_pointer_cast<CTexture2D>( _ResrcMan.FindObj(iter->second) ).get();
            if (pTex2D)
            {
                pSRVar = GetShaderVariable("DiffuseTexture")->AsShaderResource();
                V_RETURN( pSRVar->SetResource(pTex2D->GetShaderResourceView()) ); 
                V_RETURN( pScalarVar->SetBool(true) );
            }
        }
        else
        {
            pVecVar = GetShaderVariable("Kd")->AsVector();
            V_RETURN( pVecVar->SetFloatVector(pMaterial->diffuse) );
            V_RETURN( pScalarVar->SetBool(false) );
        }

        //set specular texture
        pScalarVar = GetShaderVariable("HasSpecularTexture")->AsScalar();
        if ((iter = pMaterial->textureSlots.find("specular")) != pMaterial->textureSlots.end())
        {
            CTexture2D *pTex2D = boost::dynamic_pointer_cast<CTexture2D>( _ResrcMan.FindObj(iter->second) ).get();
            if (pTex2D)
            { 
                pSRVar = GetShaderVariable("SpecularTexture")->AsShaderResource();
                V_RETURN( pSRVar->SetResource(pTex2D->GetShaderResourceView()) ); 
                V_RETURN( pScalarVar->SetBool(true) );
            }
        }
        else
        {
            pVecVar = GetShaderVariable("Ks")->AsVector();
            V_RETURN( pVecVar->SetFloatVector(pMaterial->specular) );
            V_RETURN( pScalarVar->SetBool(false) );
        }

        //set specularity
        pScalarVar = GetShaderVariable("MaterialSpecularity")->AsScalar();
        V_RETURN( pScalarVar->SetFloat(pMaterial->specularity) );

        //set alpha texture
        pScalarVar = GetShaderVariable("HasAlphaTexture")->AsScalar();
        if ((iter = pMaterial->textureSlots.find("alpha")) != pMaterial->textureSlots.end())
        {
            CTexture2D *pTex2D = boost::dynamic_pointer_cast<CTexture2D>( _ResrcMan.FindObj(iter->second) ).get();
            if (pTex2D)
            { 
                pSRVar = GetShaderVariable("AlphaTexture")->AsShaderResource();
                V_RETURN( pSRVar->SetResource(pTex2D->GetShaderResourceView()) ); 
                V_RETURN( pScalarVar->SetBool(true) );
            }
        }
        else
        {
            pScalarVar2 = GetShaderVariable("MaterialAlpha")->AsScalar();
            V_RETURN( pScalarVar2->SetFloat(pMaterial->alpha) );
            V_RETURN( pScalarVar->SetBool(false) );
        }
    }
    else if ("Color" == strTechnique)
    {
        ID3D10EffectVectorVariable *pVecVar;
        pVecVar = GetShaderVariable("Kd")->AsVector();
        V_RETURN( pVecVar->SetFloatVector(pMaterial->diffuse) );
    }
    return S_OK;
}

}}} // namespaces